package com.cxs.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cxs.common.dto.MenuDto;
import com.cxs.common.dto.NodeDto;
import com.cxs.common.lang.Const;
import com.cxs.entity.Permission;
import com.cxs.entity.Role;
import com.cxs.entity.User;
import com.cxs.mapper.PermissionMapper;
import com.cxs.mapper.UserMapper;
import com.cxs.service.IPermissionService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cxs.service.IRoleService;
import com.cxs.service.IUserService;
import com.cxs.utils.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author chaoxiaoshu
 * @since 2022-06-08
 */
@Service
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permission> implements IPermissionService {

    @Autowired
    UserMapper userMapper;

    @Autowired
    PermissionMapper permissionMapper;

    @Autowired
    IUserService userService;

    @Autowired
    IRoleService roleService;

    @Autowired
    RedisUtil redisUtil;

    @Override
    public List<Permission> findAllMenu(int[] types) {
        QueryWrapper<Permission> query = new QueryWrapper<>();
        for (int type : types) {
            query.eq("type", type).or();
        }
        return list(query);
    }


    @Override
    public List<Permission> findMenusByUserId(Long userId) {
        return permissionMapper.findMenusByUserId(userId);
    }

    @Override
    public List<Permission> findPermissionsByUserId(Long userId) {
        return permissionMapper.findPermissionsByUserId(userId);
    }


    @Override
    public String getAuthorityByUserId(Long userId) {
        String authority = null;
        // 获取用户
        User user = userService.getById(userId);
        // 通过用户id获取角色列表
        List<Role> roles = roleService.findRolesByUserId(userId);
        if (roles.size() > 0) {
            String roleStr = roles.stream().map(r -> "ROLE_" + r.getCode()).collect(Collectors.joining(","));
            // 通过用户id获取权限列表
            List<Permission> permissions = findPermissionsByUserId(userId);
            String permStr = permissions.stream().map(p -> p.getPerms()).collect(Collectors.joining(","));
            authority = roleStr.concat(permStr);
        }
        return authority;
    }


    @Override
    public List<MenuDto> getMenu(Long userId) {
        List<Permission> perms = null;
        if (userId == null) {
            // 获取所有菜单
            perms = findAllMenu(new int[] {Const.MENU_TYPE_MENU, Const.MENU_TYPE_PARENT});
        } else {
            // 获取指定用户的菜单
            perms = findMenusByUserId(userId);
        }
        // 把菜单数据转成树形结构
        List<Permission> permissions = buildTree(perms);
        // 转换dto
        return convertToMenu(permissions);
    }

    @Override
    public List<NodeDto> getNodes() {
        List<Permission> tree = buildTree(this.list());
        return convertToNode(tree);
    }

    @Override
    public List<Permission> buildTree(List<Permission> permissions) {
        List<Permission> tree = new ArrayList<>();
        for (Permission permission : permissions) {
            List<Permission> children = new ArrayList<>();
            // 把所有子节点添加到对应的父节点的children属性里
            for (Permission p : permissions) {
                // 遍历权限列表，如果该权限的父Id等于permission的id，则添加到children中
                if (p.getParentId() == permission.getId()) {
                    children.add(p);
                }
            }
            permission.setChildren(children);
            // 把顶级父节点添加到menu中
            if (permission.getParentId() == 0L) {
                tree.add(permission);
            }
        }
        return tree;
    }

    /**
     * permission转menuDto
     * @param perms
     * @return
     */
    private List<MenuDto> convertToMenu(List<Permission> perms) {
        List<MenuDto> menuDtos = new ArrayList<>();
        perms.forEach(perm -> {
            MenuDto dto = new MenuDto();
            dto.setId(perm.getId());
            dto.setName(perm.getPerms());
            dto.setTitle(perm.getName());
            dto.setComponent(perm.getComponent());
            dto.setIcon(perm.getIcon());
            dto.setPath(perm.getPath());
            if (perm.getChildren().size() > 0) {
                dto.setChildren(convertToMenu(perm.getChildren()));
            }
            menuDtos.add(dto);
        });
        return menuDtos;
    }

    /**
     * permission转nodeDto
     * @param perms
     * @return
     */
    private List<NodeDto> convertToNode(List<Permission> perms) {
        List<NodeDto> nodes = new ArrayList<>();
        perms.forEach(perm -> {
            NodeDto node = new NodeDto();
            node.setId(perm.getId());
            node.setLabel(perm.getName());
            if (perm.getChildren().size() > 0) {
                node.setChildren(convertToNode(perm.getChildren()));
            }
            nodes.add(node);
        });
        return nodes;
    }



    @Override
    public void clearCacheByPermissionId(Long permissionId) {
        clearCacheByUsers(userMapper.findUsersByPermissionId(permissionId));
    }

    @Override
    public void clearCacheByRoleId(Long roleId) {
        clearCacheByUsers(userMapper.findUsersByRoleId(roleId));

    }

    private void clearCacheByUsers(List<User> users) {
        for (User user : users) {
            redisUtil.hdel(Const.CACHE_KEY_NAV, user.getUsername());
        }
    }
}
